package db

import (
	"database/sql"
	"fmt"
	"strings"

	_ "github.com/go-sql-driver/mysql"
	"github.com/hjl/db/glog"
	"github.com/hjl/db/utils"
	"github.com/hjl/db/zwrapper/broker"
)

var logger = glog.New("../workdb.log")

type DBWorker struct {
	DSN    string            // 数据源名称
	DB     *sql.DB           // 数据库连接句柄
	Tables map[string]*Table // 表名到表对象的映射
	DBName string            // 数据库名
}

var g_dbworker *DBWorker // 全局唯一实例

const MAX_CONSUMER = 5

type sm_s struct {
	stmt *sql.Stmt
	str  string
}

var g_stmtch = make(chan *sm_s, MAX_CONSUMER)

// 启动数据库
func StartServ() {
	// 读取配置
	host := utils.GetString("DB_IP")
	port := utils.GetString("DB_PORT")
	user := utils.GetString("DB_USER")
	passwd := utils.GetString("DB_PASSWD")
	dbname := utils.GetString("DB_NAME")
	hostId := utils.GetString("hostId")
	sqlpath := utils.GetString("DB_SQL_STMT")
	host = strings.Replace(host, "\"", "", -1)
	port = strings.Replace(port, "\"", "", -1)
	user = strings.Replace(user, "\"", "", -1)
	passwd = strings.Replace(passwd, "\"", "", -1)
	dbname = strings.Replace(dbname, "\"", "", -1)
	merger_dbname := fmt.Sprintf("%s_%s", hostId, dbname)
	sqlpath = strings.Replace(sqlpath, "\"", "", -1)
	fmt.Printf("backend host: %s:%s\n", host, port)

	// 构造 DSN 并建立数据库连接
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True", user, passwd, host, port, dbname)
	g_dbworker = &DBWorker{
		DSN:    dsn,
		Tables: make(map[string]*Table),
		DBName: merger_dbname,
	}
	fmt.Println("DSN:===", g_dbworker.DSN)

	dbobj, err := sql.Open("mysql", g_dbworker.DSN)
	if err != nil {
		logger.Fatal("[Start]: error=%v", err)
	}
	defer dbobj.Close()
	g_dbworker.DB = dbobj

	// Ping 验证连接是否有效
	err = g_dbworker.DB.Ping()
	if err != nil {
		logger.Fatal("[Start]: error=%v", err)
	}

	//创建数据库(如果不存在)
	InitDBByName(merger_dbname)

	//创建所有的表结构
	InitTables(sqlpath)

	//开始进入主循环
	StartWork()
}

// 初始化数据库
func InitDBByName(dbname string) {
	//创建 utf8mb4 编码的数据库
	str := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default character set utf8mb4;", dbname)
	// 执行sql语句
	if !SingleExecStr(str) {
		logger.Fatal("[InitDBByName]: create table error")
	}
	logger.Info("[InitDBByName]: ok.")
	fmt.Println("initialize db ..")
}

func SingleExecStr(query string) bool {
	stmt, err := g_dbworker.DB.Prepare(query)
	if err != nil {
		logger.Error("[SingleExec]: query=%s, error=%v", query, err)
		return false
	}
	defer stmt.Close()

	_, err1 := stmt.Exec()
	if err1 != nil {
		logger.Error("[SingleExec]: query=%s, error=%v", query, err1)
		return false
	}
	return true
}

func SingleExecStmt(stmt *sql.Stmt, str string) {
	defer stmt.Close()
	_, err := stmt.Exec()
	if err != nil {
		logger.Error("[SingleExecStmt]: error=%v, str=%s", err, str)
	}
}

func ExecStr(str string) bool {
	stmt, err := g_dbworker.DB.Prepare(str)
	if err != nil {
		logger.Error("[ExecStr]: str=%s, error=%v", str, err)
		return false
	}

	//stmt 可以并行执行
	g_stmtch <- &sm_s{
		stmt: stmt,
		str:  str,
	}
	return true
}

func StartWork() {
	//开始并行处理stmt
	for i := 0; i < MAX_CONSUMER; i++ {
		go StartExecStmt()
	}

	// 从通道中读取sql操作
	for work := range broker.Inputch_work() {
		Insert(work)
	}
}

func StartExecStmt() {
	for st := range g_stmtch {
		SingleExecStmt(st.stmt, st.str)
	}
}
